using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Nwc.XmlRpc;
using Org.BouncyCastle;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Crypto.Signers;
using System.Security.Cryptography;
using System.Text;
using System.ComponentModel;
using System.IO;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Engines;
using System.Collections;
using System.Net;
using System.Xml;
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.Pkcs;
using Org.BouncyCastle.Asn1.X509;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Utilities.Encoders;
using Org.BouncyCastle.Crypto.Encodings;
using Org.BouncyCastle.X509;
using Org.BouncyCastle.Crypto.Generators;

// http://xmlrpccs.sourceforge.net/

namespace Scarfy.Core.Data
{
    public class MoodleRequest : XmlRpcRequest
    {
        private static String mPublicKey;
        private static String mPrivateKey;

        public static String PublicKey { get { return mPublicKey; } }
        public static String PrivateKey { get { return mPrivateKey; } }
        public static String wwwRoot;
        public static String appName = "MoodleCSharp";

        public String RemoteWwwRoot;

        public MoodleRequest(String RemoteWwwRoot)
        {

        }

        public static void SetKeys(String Certificate)
        {
            String PublicKey = Certificate.Substring(Certificate.IndexOf("-----BEGIN CERTIFICATE-----"));
            PublicKey = PublicKey.Remove(PublicKey.IndexOf("-----END CERTIFICATE-----") + "-----END CERTIFICATE-----".Length).Trim();
            MoodleRequest.mPublicKey = PublicKey;

            String PrivateKey = Certificate.Substring(Certificate.IndexOf("-----BEGIN RSA PRIVATE KEY-----"));
            PrivateKey = PrivateKey.Remove(PrivateKey.IndexOf("-----END RSA PRIVATE KEY-----") + "-----END RSA PRIVATE KEY-----".Length).Trim();
            MoodleRequest.mPrivateKey = PrivateKey;
        }

        public static String MnetGetPublicKey(String wwwHost)
        {
            MoodleRequest client = new MoodleRequest(wwwHost);
            client.MethodName = "system/keyswap";
            client.Params.Clear();
            client.Params.Add(MoodleRequest.wwwRoot);
            client.Params.Add(MoodleRequest.PublicKey);
            client.Params.Add(MoodleRequest.appName);
            XmlRpcResponse response = client.Send(wwwHost + "/mnet/xmlrpc/server.php");

            if (response.IsFault)
                return null;

            return (String)response.Value;
        }

        public static void SetKeys(String PublicKey, String PrivateKey)
        {
            if (!String.IsNullOrEmpty(PublicKey))
            {
                if (!PublicKey.StartsWith("-----BEGIN CERTIFICATE-----"))
                    PublicKey = "-----BEGIN CERTIFICATE-----" + PublicKey;
                if (!PublicKey.EndsWith("-----END CERTIFICATE-----"))
                    PublicKey = PublicKey + "-----END CERTIFICATE-----";
                MoodleRequest.mPublicKey = PublicKey;
            }

            if (!String.IsNullOrEmpty(PrivateKey))
            {
                if (!PrivateKey.StartsWith("-----BEGIN RSA PRIVATE KEY-----"))
                    PrivateKey = "-----BEGIN RSA PRIVATE KEY-----" + PublicKey;
                if (!PrivateKey.EndsWith("-----END RSA PRIVATE KEY-----"))
                    PrivateKey = PrivateKey + "-----END RSA PRIVATE KEY-----";
                MoodleRequest.mPrivateKey = PrivateKey;
            }
        }

        private static void SetWwwRootFromPublicKey()
        {
            Asn1InputStream asn1is = new Asn1InputStream(Convert.FromBase64String(PublicKey));
            Asn1Sequence obj = (Asn1Sequence)asn1is.ReadObject();
            X509CertificateStructure x509 = X509CertificateStructure.GetInstance(obj);

            X509Name subject = x509.Subject;
            ArrayList CNs = subject.GetValues(X509Name.CN);
            String wwwRoot = (String)CNs[0];
        }

        public static string TimeStamp()
        {
            // Default implementation of UNIX time of the current UTC time
            TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
            return Convert.ToInt64(ts.TotalSeconds).ToString();
        }

        public static String GenerateCertificate(String wwwHost)
        {
            RsaKeyPairGenerator keygen = new RsaKeyPairGenerator();
            //This is quite slow
            KeyGenerationParameters p = new KeyGenerationParameters(new SecureRandom(), 2048);
            keygen.Init(p);
            //This is a particularly slow operation
            AsymmetricCipherKeyPair keypair = keygen.GenerateKeyPair();
            
            X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
            TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
            long SerialNumber = Convert.ToInt64(ts.TotalSeconds);
            certGen.SetSerialNumber(BigInteger.ValueOf(SerialNumber));

            Hashtable attrs = new Hashtable();
            attrs[X509Name.CN] = wwwHost;
            ArrayList ord = new ArrayList();
            ord.Add(X509Name.CN);
            ArrayList values = new ArrayList();
            values.Add(wwwHost);

            certGen.SetIssuerDN(new X509Name(ord, attrs));
            certGen.SetNotBefore(DateTime.UtcNow.AddDays(-1));
            certGen.SetNotAfter(DateTime.UtcNow.AddDays(28));
            certGen.SetSubjectDN(new X509Name(ord, attrs));
            certGen.SetPublicKey(keypair.Public);
            certGen.SetSignatureAlgorithm("SHA1WithRSAEncryption");

            X509Certificate cert = certGen.Generate(keypair.Private);
            cert.CheckValidity();
            cert.Verify(keypair.Public);

            StringWriter sw = new StringWriter();
            PemWriter writer = new PemWriter(sw);
            writer.WriteObject(cert);
            writer.WriteObject(keypair.Private);
            writer.Writer.Close();
            String output = sw.ToString();

            return output;
        }
    }

    public class MoodleResponse : XmlRpcResponse
    {

    }

    public class MoodleAuth
    {
        public String PublicKey = @"-----BEGIN CERTIFICATE-----
MIIDKDCCApGgAwIBAgIJAKAhBSBxSpyNMA0GCSqGSIb3DQEBBQUAMGwxCzAJBgNV
BAYTAk5aMRMwEQYDVQQIEwpDYW50ZXJidXJ5MRUwEwYDVQQHEwxDaHJpc3RjaHVy
Y2gxDzANBgNVBAoTBlNjYXJmeTEgMB4GA1UEAxMXaHR0cDovL3d3dy5zY2FyZnku
Y28ubnowHhcNMTAwMTA3MDIyMzUyWhcNMTEwMTA3MDIyMzUyWjBsMQswCQYDVQQG
EwJOWjETMBEGA1UECBMKQ2FudGVyYnVyeTEVMBMGA1UEBxMMQ2hyaXN0Y2h1cmNo
MQ8wDQYDVQQKEwZTY2FyZnkxIDAeBgNVBAMTF2h0dHA6Ly93d3cuc2NhcmZ5LmNv
Lm56MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQD9wp2lMLpD2YlLrFntiENo
QhuS8KJhlWZb59qP7hE4+4WH8DVsh5YlAr5921EposyLc8GLwuSh/u1gf4CWGKC0
7no79bDyH72Xv2KmidkerlxjbwSmF7ZCFyckxf9mlfx7ael11ro7pEpRZQsZ0MIa
oOUtWvRyIHGwpjG93rIVxwIDAQABo4HRMIHOMB0GA1UdDgQWBBTqHHwymfIaqtZQ
sLSTeqbd1HFAszCBngYDVR0jBIGWMIGTgBTqHHwymfIaqtZQsLSTeqbd1HFAs6Fw
pG4wbDELMAkGA1UEBhMCTloxEzARBgNVBAgTCkNhbnRlcmJ1cnkxFTATBgNVBAcT
DENocmlzdGNodXJjaDEPMA0GA1UEChMGU2NhcmZ5MSAwHgYDVQQDExdodHRwOi8v
d3d3LnNjYXJmeS5jby5ueoIJAKAhBSBxSpyNMAwGA1UdEwQFMAMBAf8wDQYJKoZI
hvcNAQEFBQADgYEA4xLCAe3HStVGoXPovLRAk5vjx3yBS2uNVzOtpmxMMnOLR6zp
gwAKYPhKx+yXJ+zONUEkrGFrgscgpk9aLyD9BY7DocgpLiiYZSh+LeGNg/9qiGpB
Sfx6a5yHmzlAtEFfXr+GcI5MhqAQD3L8gRgEi113IB+OXndqyuoVeq3Fi+4=
-----END CERTIFICATE-----
";
        public String PrivateKey = @"-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQD9wp2lMLpD2YlLrFntiENoQhuS8KJhlWZb59qP7hE4+4WH8DVs
h5YlAr5921EposyLc8GLwuSh/u1gf4CWGKC07no79bDyH72Xv2KmidkerlxjbwSm
F7ZCFyckxf9mlfx7ael11ro7pEpRZQsZ0MIaoOUtWvRyIHGwpjG93rIVxwIDAQAB
AoGAaLb6nsQw2PbXtSZ2JZLpXgiJoGU0XNht2NcgVeyDpuQEAkiZgyOgTb2IJh9u
qqPHjHREFgxilIbCJeP3h/i5t52mSdZ22Kktyu6kkhyJxVq8eKNjFdI5OTMa66yi
0P1r+JGdFgMfB2mh5Wb7dCGMxlmokapOFwqeoUkJzvTKM+ECQQD/dDAI87q0n412
bwDK/E7X6ZC7uVHVOu4K7cUXNPyTgpbtYp75NFYjKRDhPfDLEIkq6qo8Os6FaIip
6IOKWlDTAkEA/k2AT+/ZZr1fLCRLu1egH7yDQzgBx26chEpZNlIuB85Plt1TIjya
8YlP4SDsnor8Smg2E7V/x4Kp0zZCB3euvQJAKlWqBEHIJljuy7rXqcwokNWvW7z5
l9ndS0heSltIpHWW555ZdDk9MTSEDKAEQNLruIYNUk/4m9lYFLho3EvdawJBAMvn
zrvJ4PL9Y0OcstC72Ru5ZzLNxLdpnLyCdPgWeuwtZCneu1sXZ1HGvTMR2EjjvpnW
5410GcoanhtKRTWBpK0CQEI6I/nv4FDMePsJPaZV58z5f4bp3L1K0MZeCWflcgtZ
UJXGzxQRmVtm8A0F6beC9HznOfaqyhD+Y4drMaAT4H4=
-----END RSA PRIVATE KEY-----
";

        public String wwwRoot = "http://www.scarfy.co.nz";  //MUST match the certificate CN
        public String appName = "scarfy";

        public MoodleAuth()
        {
            //TODO load the public/private keys from a database/file
        }

        public static void RunTests()
        {
            MoodleAuth moodle = new MoodleAuth();

            //Verify encryption/decryption works
            String msg = moodle.MnetEncryptMessage("Hello", moodle.PublicKey);
            String msg2 = moodle.MnetDecryptMessage(msg);


            String RemotePublicKey = moodle.MnetGetPublicKey("http://millie.id.co.nz/moodle");

            XmlRpcRequest client = new XmlRpcRequest();
            client.MethodName = "system/keyswap";
            client.Params.Clear();
            client.Params.Add(moodle.wwwRoot);
            client.Params.Add(moodle.PublicKey);
            client.Params.Add(moodle.appName);

            String request = client.ToString();
            request = moodle.MnetSignMessage(request);
            request = moodle.MnetEncryptMessage(request, RemotePublicKey);
            XmlRpcResponse response = moodle.XmlRpcSendRequest(request, "http://millie.id.co.nz/moodle", RemotePublicKey);


            // 7015 = forbidden method

        }

        public String XmlRpcEncodeRequest(String Method, IList Parameters)
        {
            XmlRpcRequest client = new XmlRpcRequest(Method, Parameters);
            return client.ToString();
        }

        public XmlRpcResponse XmlRpcSendRequest(String XMLData, String RemoteWwwRoot, String RemoteCertificate)
        {
            String url = RemoteWwwRoot + "/mnet/xmlrpc/server.php";
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
            if (request == null)
                throw new XmlRpcException(XmlRpcErrorCodes.TRANSPORT_ERROR,
                              XmlRpcErrorCodes.TRANSPORT_ERROR_MSG + ": Could not create request with " + url);
            request.Method = "POST";
            request.ContentType = "text/xml";
            request.AllowWriteStreamBuffering = true;

            Stream stream = request.GetRequestStream();
            XmlTextWriter xml = new XmlTextWriter(stream, ASCIIEncoding.ASCII);
            xml.WriteRaw(XMLData);
            xml.Flush();
            xml.Close();

            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            StreamReader input = new StreamReader(response.GetResponseStream());
            String data = input.ReadToEnd();

            if (data.Substring(0, 100).Contains("<encryptedMessage>"))
            {
                //decrypt the encrypted message here
                data = MnetDecryptMessage(data);
            }
            if (data.Substring(0, 100).Contains("<signedMessage>"))
            {
                //unsign the signed message here
                data = MnetUnsignMessage(data, RemoteCertificate);
            }

            XmlRpcResponse resp = (XmlRpcResponse)new XmlRpcResponseDeserializer().Deserialize(data);
            input.Close();
            response.Close();
            return resp;
        }

        public String MnetDecryptMessage(String xmlData)
        {
            // To decrypt:
            // 1. Decrypt the key using RSA and your private key
            // 2. Decrypt the data using RC4 and the decrypted key

            XmlDocument doc = new XmlDocument();
            XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
            nsmgr.AddNamespace("a", "http://www.w3.org/2001/04/xmlenc#");
            doc.LoadXml(xmlData);

            XmlNode keynode = doc.SelectSingleNode("//a:EncryptedKey/a:CipherData/a:CipherValue", nsmgr);
            XmlNode datanode = doc.SelectSingleNode("//a:EncryptedData/a:CipherData/a:CipherValue", nsmgr);
            byte[] cipherKey = Convert.FromBase64String(keynode.InnerText);
            byte[] cipherText = Convert.FromBase64String(datanode.InnerText);

            // Decrypt the cipherKey using our RSA private key
            RsaKeyParameters privKey = GetPrivateKey(this.PrivateKey);

            // PHP uses PKCS1 encoding
            IAsymmetricBlockCipher rsa = new Pkcs1Encoding(new RsaEngine());
            rsa.Init(false, privKey);
            byte[] plainKey = rsa.ProcessBlock(cipherKey, 0, cipherKey.Length);

            //use the key to decrypt the rc4 data
            byte[] plainText = new byte[cipherText.Length];
            RC4Engine rc4 = new RC4Engine();
            KeyParameter rc4key = ParameterUtilities.CreateKeyParameter("RC4", plainKey);
            rc4.Init(false, rc4key);
            rc4.ProcessBytes(cipherText, 0, cipherText.Length, plainText, 0);

            return System.Text.ASCIIEncoding.ASCII.GetString(plainText);
        }

        public String MnetUnsignMessage(String xmlData, String RemoteCertificate)
        {
            XmlDocument doc = new XmlDocument();
            XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
            nsmgr.AddNamespace("s", "http://www.w3.org/2000/09/xmldsig#");
            doc.LoadXml(xmlData);

            XmlNode digestNode = doc.SelectSingleNode("//s:DigestValue", nsmgr);
            XmlNode sigNode = doc.SelectSingleNode("//s:Signature/s:SignatureValue", nsmgr);
            XmlNode wwwNode = doc.SelectSingleNode("//wwwroot");
            XmlNode timeNode = doc.SelectSingleNode("//timestamp");
            XmlNode objNode = doc.SelectSingleNode("//object");

            String Message = base64Decode(objNode.InnerText);
            String digest = sha1(Message);
            if (digestNode.InnerText != digest)
            {
                //failed the first test
                throw new ArgumentException("SHA1 digest does not match");
            }

            RsaKeyParameters remotepubkey = GetPublicKey(RemoteCertificate);

            //Use their public key to test the signature
            ISigner sig = SignerUtilities.GetSigner("SHA1WithRSAEncryption");
            sig.Init(false, remotepubkey);
            byte[] Signature = Convert.FromBase64String(sigNode.InnerText);
            sig.BlockUpdate(Encoding.ASCII.GetBytes(Message), 0, Message.Length);
            if (!sig.VerifySignature(Signature))
            {
                //failed second test
                throw new ArgumentException("Signature does not match the public key");
            }

            return Message;
        }

        public String MnetGetPublicKey(String wwwHost)
        {
            XmlRpcRequest client = new XmlRpcRequest();
            client.MethodName = "system/keyswap";
            client.Params.Clear();
            client.Params.Add(this.wwwRoot);
            client.Params.Add(this.PublicKey);
            client.Params.Add(this.appName);
            XmlRpcResponse response = client.Send(wwwHost + "/mnet/xmlrpc/server.php");

            if (response.IsFault)
                return null;

            return (String) response.Value;
        }

        public String MnetSignMessage(String Message)
        {
            String Digest = sha1(Message);

            // Convert Private Key string into a usable object
            RsaKeyParameters privKey = GetPrivateKey(this.PrivateKey);

            ISigner sig = SignerUtilities.GetSigner("SHA1WithRSAEncryption");
            sig.Init(true, privKey);
            sig.BlockUpdate(Encoding.ASCII.GetBytes(Message), 0, Message.Length);
            byte[] Signature = sig.GenerateSignature();

            String SignedMessage = @"<?xml version=""1.0"" encoding=""iso-8859-1""?>
                <signedMessage>
                    <Signature Id=""MoodleSignature"" xmlns=""http://www.w3.org/2000/09/xmldsig#"">
                        <SignedInfo>
                            <CanonicalizationMethod Algorithm=""http://www.w3.org/TR/2001/REC-xml-c14n-20010315""/>
                            <SignatureMethod Algorithm=""http://www.w3.org/2000/09/xmldsig#dsa-sha1""/>
                            <Reference URI=""#XMLRPC-MSG"">
                                <DigestMethod Algorithm=""http://www.w3.org/2000/09/xmldsig#sha1""/>
                                <DigestValue>" + Digest + @"</DigestValue>
                            </Reference>
                        </SignedInfo>
                        <SignatureValue>" + Convert.ToBase64String(Signature) + @"</SignatureValue>
                        <KeyInfo>
                            <RetrievalMethod URI=""" + wwwRoot + @"/mnet/publickey.php""/>
                        </KeyInfo>
                    </Signature>
                    <object ID=""XMLRPC-MSG"">" + base64Encode(Message) + @"</object>
                    <wwwroot>" + wwwRoot + @"</wwwroot>
                    <timestamp>" + TimeStamp() + @"</timestamp>
                </signedMessage>";

            return SignedMessage;
        }

        public static RsaKeyParameters GetPublicKey(String Certificate)
        {
            if (Certificate == null)
                throw new NullReferenceException("Certificate is null.  Probably has mnet disabled.");

            //convert the cert into the usable base64 bit
            String PublicKey = Certificate.Substring(Certificate.IndexOf("-----BEGIN CERTIFICATE-----") + "-----BEGIN CERTIFICATE-----".Length);
            PublicKey = PublicKey.Remove(PublicKey.IndexOf("-----END CERTIFICATE-----")).Trim();

            Asn1InputStream asn1is = new Asn1InputStream(Convert.FromBase64String(PublicKey));
            Asn1Sequence obj = (Asn1Sequence)asn1is.ReadObject();
            X509CertificateStructure x509 = X509CertificateStructure.GetInstance(obj);
            SubjectPublicKeyInfo keyinfo = x509.SubjectPublicKeyInfo;
            RsaPublicKeyStructure key = RsaPublicKeyStructure.GetInstance(keyinfo.GetPublicKey());

            RsaKeyParameters pubkey = new RsaKeyParameters(false, key.Modulus, key.PublicExponent);
            return pubkey;
        }

        public static RsaKeyParameters GetPrivateKey(String Certificate)
        {
            // Strip out all the chuff and just use the base64 string
            String PrivateKey = Certificate.Substring(Certificate.IndexOf("-----BEGIN RSA PRIVATE KEY-----") + "-----BEGIN RSA PRIVATE KEY-----".Length);
            PrivateKey = PrivateKey.Remove(PrivateKey.IndexOf("-----END RSA PRIVATE KEY-----")).Trim();

            // Convert Private Key string into a usable object
            Asn1InputStream asn1is = new Asn1InputStream(Convert.FromBase64String(PrivateKey));
            RsaPrivateKeyStructure key = new RsaPrivateKeyStructure((Asn1Sequence)asn1is.ReadObject());

            RsaKeyParameters privKey = new RsaKeyParameters(true, key.Modulus, key.PrivateExponent);
            return privKey;
        }

        public String MnetEncryptMessage(String Message, String RemoteCertificate)
        {
            byte[] EncryptedMessage = new byte[Message.Length];
            byte[] EncryptedKey;

            
            //'seal' the message using their public key

            //how to 'seal a message':
            //  1. generate a random 128bit secret key
            CipherKeyGenerator keygen = new CipherKeyGenerator();
            KeyGenerationParameters p = new KeyGenerationParameters(new SecureRandom(), 128);
            keygen.Init(p);
            byte[] SecretKey = keygen.GenerateKey();

            //  2. encrypt the data symmetrically with rc4 using the random key
            RC4Engine rc4 = new RC4Engine();
            rc4.Init(true, ParameterUtilities.CreateKeyParameter("RC4", SecretKey));
            rc4.ProcessBytes(System.Text.Encoding.ASCII.GetBytes(Message), 0, Message.Length, EncryptedMessage, 0);

            //  3. encrypt the random key itself with rsa using the public key/certificate
            // PHP uses PKCS1 encoding
            RsaKeyParameters remotepubkey = GetPublicKey(RemoteCertificate);
            IAsymmetricBlockCipher rsa = new Pkcs1Encoding(new RsaEngine());
            rsa.Init(true, remotepubkey);
            int blocksize = rsa.GetInputBlockSize();
            List<byte> output = new List<byte>();
            for (int i = 0; i < SecretKey.Length; i+= blocksize)
            {
                int chunkSize = Math.Min(blocksize, SecretKey.Length - (i * blocksize));
                output.AddRange(rsa.ProcessBlock(SecretKey, i, chunkSize));
            }
            EncryptedKey = output.ToArray();

            String XMLEncryptedMessage = @"<?xml version=""1.0"" encoding=""iso-8859-1""?>
                <encryptedMessage>
                    <EncryptedData Id=""ED"" xmlns=""http://www.w3.org/2001/04/xmlenc#"">
                        <EncryptionMethod Algorithm=""http://www.w3.org/2001/04/xmlenc#arcfour""/>
                        <ds:KeyInfo xmlns:ds=""http://www.w3.org/2000/09/xmldsig#"">
                            <ds:RetrievalMethod URI=""#EK"" Type=""http://www.w3.org/2001/04/xmlenc#EncryptedKey""/>
                            <ds:KeyName>XMLENC</ds:KeyName>
                        </ds:KeyInfo>
                        <CipherData>
                            <CipherValue>" + Convert.ToBase64String(EncryptedMessage) + @"</CipherValue>
                        </CipherData>
                    </EncryptedData>
                    <EncryptedKey Id=""EK"" xmlns=""http://www.w3.org/2001/04/xmlenc#"">
                        <EncryptionMethod Algorithm=""http://www.w3.org/2001/04/xmlenc#rsa-1_5""/>
                        <ds:KeyInfo xmlns:ds=""http://www.w3.org/2000/09/xmldsig#"">
                            <ds:KeyName>SSLKEY</ds:KeyName>
                        </ds:KeyInfo>
                        <CipherData>
                            <CipherValue>" + Convert.ToBase64String(EncryptedKey) + @"</CipherValue>
                        </CipherData>
                        <ReferenceList>
                            <DataReference URI=""#ED""/>
                        </ReferenceList>
                        <CarriedKeyName>XMLENC</CarriedKeyName>
                    </EncryptedKey>
                    <wwwroot>" + wwwRoot + @"</wwwroot>
                </encryptedMessage>";
            return XMLEncryptedMessage;
        }

        public static string sha1(string text)
        {
            byte[] original_bytes = System.Text.Encoding.ASCII.GetBytes(text);
            byte[] encoded_bytes = new SHA1CryptoServiceProvider().ComputeHash(original_bytes);
            StringBuilder result = new StringBuilder();
            for (int i = 0; i < encoded_bytes.Length; i++)
            {
                result.Append(encoded_bytes[i].ToString("x2"));
            }
            return result.ToString();
        }

        public string base64Encode(string data)
        {
            try
            {
                byte[] encData_byte = new byte[data.Length];
                encData_byte = System.Text.Encoding.UTF8.GetBytes(data);    
                string encodedData = Convert.ToBase64String(encData_byte);
                return encodedData;
            }
            catch(Exception e)
            {
                throw new Exception("Error in base64Encode" + e.Message);
            }
        }

        public string base64Decode(string data)
        {
            try
            {
                System.Text.UTF8Encoding encoder = new System.Text.UTF8Encoding();
                System.Text.Decoder utf8Decode = encoder.GetDecoder();

                byte[] todecode_byte = Convert.FromBase64String(data);
                int charCount = utf8Decode.GetCharCount(todecode_byte, 0, todecode_byte.Length);
                char[] decoded_char = new char[charCount];
                utf8Decode.GetChars(todecode_byte, 0, todecode_byte.Length, decoded_char, 0);
                string result = new String(decoded_char);
                return result;
            }
            catch (Exception e)
            {
                throw new Exception("Error in base64Decode" + e.Message);
            }
        }

        public static string TimeStamp()
        {
            // Default implementation of UNIX time of the current UTC time
            TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
            return Convert.ToInt64(ts.TotalSeconds).ToString();
        }
    }
}
